﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Localization;
using Abp.Notifications;
using Abp.Organizations;
using Abp.Runtime.Session;
using Abp.UI;
using Abp.Zero.Configuration;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Mt.Organizations;
using Mt.Site.Application.Authorization.Permissions;
using Mt.Site.Application.Authorization.Permissions.Dto;
using Mt.Site.Application.Authorization.Users.Dto;
using Mt.Site.Application.Authorization.Users.Exporting;
using Mt.Site.Application.Dto;
using Mt.Site.Application.Organizations;
using Mt.Site.Application.Organizations.Dto;
using Mt.Site.Application.Url;
using Mt.Site.Core.Authorization;
using Mt.Site.Core.Authorization.Users;
using Mt.Site.Core.Authorization.Users.Entities;
using Mt.Site.Core.Base.Authorization;
using Mt.Site.Core.Base.Authorization.Level;
using Mt.Site.Core.Base.Authorization.Roles;
using Mt.Site.Core.Base.Authorization.Users;
using Mt.Site.Core.Base.Localization;
using Mt.Site.Core.Notifications;
using Mt.Site.Core.Security;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;

namespace Mt.Site.Application.Authorization.Users
{
    [AbpAuthorize(AppPermissions.Pages_Administration_Users)]
    public class UserAppService : MtSiteAppServiceBase, IUserAppService
    {
        public IAppUrlService AppUrlService { get; set; }
        private readonly UserStore _userStore;

        private readonly RoleManager _roleManager;
        private readonly IUserEmailer _userEmailer;
        private readonly IUserListExcelExporter _userListExcelExporter;
        private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
        private readonly IAppNotifier _appNotifier;
        private readonly IRepository<RolePermissionSetting, long> _rolePermissionRepository;
        private readonly IRepository<UserPermissionSetting, long> _userPermissionRepository;
        private readonly IRepository<UserRole, long> _userRoleRepository;
        private readonly IRepository<Role> _roleRepository;
        private readonly IUserPolicy _userPolicy;
        private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
        private readonly IPasswordHasher<User> _passwordHasher;

        private readonly IApplicationLanguageManager _applicationLanguageManager;
        private readonly IPermissionAppService _permissionAppService;
        private readonly IAdministratorLevelManager _administratorLevelManager;

        private readonly IRepository<MtOrganizationUnit, long> _organizationUnitRepository;
        private readonly IRepository<UserOrganizationUnit, long> _userOrganizationUnitRepository;
        private readonly IRepository<OrganizationUnitRole, long> _organizationUnitRoleRepository;
        private readonly IRepository<UserExtension, long> _userExtensionRepository;
        private readonly IRSACryptoService _rSACryptoService;

        public UserAppService(
            RoleManager roleManager,
            IUserEmailer userEmailer,
            UserStore userStore,
            IUserListExcelExporter userListExcelExporter,
            INotificationSubscriptionManager notificationSubscriptionManager,
            IAppNotifier appNotifier,
            IRepository<RolePermissionSetting, long> rolePermissionRepository,
            IRepository<UserPermissionSetting, long> userPermissionRepository,
            IRepository<UserRole, long> userRoleRepository,
            IRepository<Role> roleRepository,
            IRepository<MtOrganizationUnit, long> organizationUnitRepository,
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
            IPermissionAppService permissionAppService,
            IAdministratorLevelManager administratorLevelManager,
            IUserPolicy userPolicy,
            IEnumerable<IPasswordValidator<User>> passwordValidators,
            IPasswordHasher<User> passwordHasher,
            IApplicationLanguageManager applicationLanguageManager,
            IRepository<OrganizationUnitRole, long> organizationUnitRoleRepository,
            IRepository<UserExtension, long> userExtensionRepository,
            IRSACryptoService rSACryptoService)
        {
            _roleManager = roleManager;
            _userEmailer = userEmailer;
            _userStore = userStore;
            _userListExcelExporter = userListExcelExporter;
            _notificationSubscriptionManager = notificationSubscriptionManager;
            _appNotifier = appNotifier;
            _rolePermissionRepository = rolePermissionRepository;
            _userPermissionRepository = userPermissionRepository;
            _userRoleRepository = userRoleRepository;

            _organizationUnitRepository = organizationUnitRepository;
            _userOrganizationUnitRepository = userOrganizationUnitRepository;
            _organizationUnitRoleRepository = organizationUnitRoleRepository;
            _roleRepository = roleRepository;

            _permissionAppService = permissionAppService;
            _administratorLevelManager = administratorLevelManager;
            _userPolicy = userPolicy;
            _passwordValidators = passwordValidators;
            _passwordHasher = passwordHasher;

            AppUrlService = NullAppUrlService.Instance;
            _applicationLanguageManager = applicationLanguageManager;
            _userExtensionRepository = userExtensionRepository;
            _rSACryptoService = rSACryptoService;
        }

        [HttpPost]
        public async Task<PagedResultDto<UserListDto>> GetUsers(GetUsersInput input)
        {
            var currentUser = await GetCurrentUserAsync();

            var query = GetUsersFilteredQuery(input, currentUser.AdministratorWeight);

            var userCount = await query.CountAsync();

            var users = await query
                .OrderBy(input.Sorting)
                .PageBy(input)
                .ToListAsync();

            var userListDtos = ObjectMapper.Map<List<UserListDto>>(users);
            userListDtos.ForEach(user => { user.AdministratorLevel = _administratorLevelManager.GetNameByWeight(user.AdministratorWeight); });
            await FillRoleNames(userListDtos);
            await FillUnitNames(userListDtos);

            return new PagedResultDto<UserListDto>(
                userCount,
                userListDtos
                );
        }

        public async Task<FileDto> GetUsersToExcel(GetUsersToExcelInput input)
        {
            var currentUser = await GetCurrentUserAsync();
            var query = GetUsersFilteredQuery(input, currentUser.AdministratorWeight);
            var users = await query
                .OrderBy(input.Sorting)
                .ToListAsync();
            var userListDtos = ObjectMapper.Map<List<UserListDto>>(users);
            await FillRoleNames(userListDtos);
            await FillUnitNames(userListDtos);

            return _userListExcelExporter.ExportToFile(userListDtos);
        }

        #region 详情页编辑

        //[AbpAuthorize(AppPermissions.Pages_Administration_Users_Create, AppPermissions.Pages_Administration_Users_Edit)]
        public async Task<GetUserForEditOutput> GetUserForEdit(NullableIdDto<long> input)
        {
            var userId = AbpSession.GetUserId();
            var currentUser = await UserManager.FindByIdAsync(userId.ToString());

            //Getting all available roles
            UserRoleDto[] userRoleDtos = (await _roleManager.Roles
                    .OrderBy(r => r.DisplayName)
                    .Select(r => new UserRoleDto
                    {
                        RoleId = r.Id,
                        RoleName = r.Name,
                        RoleDisplayName = r.DisplayName,
                        CreatorUserId = r.CreatorUserId
                    })
                    .ToArrayAsync());

            if (currentUser.AdministratorWeight < LevelEnum.Super.RawValue())
            {
                var roles = await _userStore.GetRolesAsync(currentUser);

                userRoleDtos = userRoleDtos.Where(c=> roles.Contains(c.RoleName) || c.CreatorUserId == currentUser.Id).ToArray();
            }

            var allOrganizationUnits = await _organizationUnitRepository.GetAllListAsync(item=>item.IsActive);
            //allOrganizationUnits = allOrganizationUnits.OrderBy(item => item.Code).ToList();
            var output = new GetUserForEditOutput
            {
                Roles = userRoleDtos,
                AllOrganizationUnits = ObjectMapper.Map<List<OrganizationUnitDto>>(allOrganizationUnits),
                MemberedOrganizationUnits = new List<string>()
            };
            output.AllOrganizationUnits = OrganizationUnitHelper.AdapterList(output.AllOrganizationUnits);
            foreach (var item in output.AllOrganizationUnits)
            {
                item.Order = Convert.ToInt32(OrganizationUnit.GetLastUnitCode(item.Code));
            }
            if (!input.Id.HasValue)
            {
                //Creating a new user
                output.User = new UserEditDto
                {
                    IsActive = true,
                    ShouldChangePasswordOnNextLogin = false,
                    IsTwoFactorEnabled = 
                        await SettingManager.GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.TwoFactorLogin.IsEnabled),
                    IsLockoutEnabled = 
                        await SettingManager.GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.UserLockOut.IsEnabled),
                    Order = await GetMaxOrderNumber()
                };

                //default role
                foreach (var defaultRole in await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync())
                {
                    var defaultUserRole = userRoleDtos.FirstOrDefault(ur => ur.RoleName == defaultRole.Name);
                    if (defaultUserRole != null)
                    {
                        defaultUserRole.IsAssigned = true;
                    }
                }
            }
            else
            {
                //Editing an existing user
                var user = await UserManager.GetUserByIdAsync(input.Id.Value);

                output.User = ObjectMapper.Map<UserEditDto>(user);
                output.ProfilePictureId = user.ProfilePictureId;

                var organizationUnits = await UserManager.GetOrganizationUnitsAsync(user);
                output.MemberedOrganizationUnits = organizationUnits.Select(ou => ou.Code).ToList();

                var allRolesOfUsersOrganizationUnits = GetAllRoleNamesOfUsersOrganizationUnits(input.Id.Value);

                foreach (var userRoleDto in userRoleDtos)
                {
                    userRoleDto.IsAssigned = await UserManager.IsInRoleAsync(user, userRoleDto.RoleName);
                    userRoleDto.InheritedFromOrganizationUnit = allRolesOfUsersOrganizationUnits.Contains(userRoleDto.RoleName);
                }

                output.AdministratorWeight = user.AdministratorWeight;
                output.AdministratorLevel = _administratorLevelManager.GetNameByWeight(user.AdministratorWeight);

                var userExtension = await _userExtensionRepository.FirstOrDefaultAsync(c => c.UserId == input.Id.Value);
                output.OrganizationUnitId = userExtension?.MainUnitId;
            }

            output.LevelOptions = _administratorLevelManager.GetSelectOptions(currentUser.AdministratorWeight);

            return output;
        }

        private List<string> GetAllRoleNamesOfUsersOrganizationUnits(long userId)
        {
            return (from userOu in _userOrganizationUnitRepository.GetAll()
                    join roleOu in _organizationUnitRoleRepository.GetAll() on userOu.OrganizationUnitId equals roleOu
                        .OrganizationUnitId
                    join userOuRoles in _roleRepository.GetAll() on roleOu.RoleId equals userOuRoles.Id
                    where userOu.UserId == userId
                    select userOuRoles.Name).ToList();
        }

        //[AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task<GetUserPermissionsForEditOutput> GetUserPermissionsForEdit(EntityDto<long> input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            var permissions = await _permissionAppService.GetAllPermissionsOrderByDisplayNameAsync();
            var grantedPermissions = await UserManager.GetGrantedPermissionsAsync(user);

            if (AbpSession.TenantId == null)
            {
                return new GetUserPermissionsForEditOutput
                {
                    GrantedPermissionNames = grantedPermissions.Select(p => p.Name).ToList(),
                    GrantedMenuPermissionNames = new List<string>(),
                    Permissions = permissions,
                    MenuPermissions = new List<FlatMenuPermissionDto>(),
                    AdministratorWeight = user.AdministratorWeight
                };
            }
            else
            {
                var grantedMenuPermissions = await UserManager.GetGrantedMenuPermissionsAsync(user);
                var menuPermissions = await _permissionAppService.GetAllMenuPermissionsAsync();

                return new GetUserPermissionsForEditOutput
                {
                    GrantedPermissionNames = grantedPermissions.Select(p => p.Name).ToList(),
                    GrantedMenuPermissionNames = grantedMenuPermissions.ToList(),
                    Permissions = permissions,
                    MenuPermissions = menuPermissions,
                    AdministratorWeight = user.AdministratorWeight
                };
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task ResetUserSpecificPermissions(EntityDto<long> input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            await UserManager.ResetAllPermissionsAsync(user, PermissionType.Permission);
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task ResetUserSpecificMenuPermissions(EntityDto<long> input)
        {
            if (AbpSession.TenantId != null)
            {
                var user = await UserManager.GetUserByIdAsync(input.Id);
                await UserManager.ResetAllPermissionsAsync(user, PermissionType.Menu);
                await UserManager.ResetAllPermissionsAsync(user, PermissionType.MenuAndPermission);
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task UpdateUserPermissions(UpdateUserPermissionsInput input)
        {
            /*
             用户不可以修改自己的权限，超级管理员不需要绑定权限
             */
            if (input.Id != AbpSession.UserId)
            {
                var user = await UserManager.GetUserByIdAsync(input.Id);
                if (user.AdministratorWeight < LevelEnum.Super.RawValue())
                {
                    var grantedPermissions = PermissionManager.GetPermissionsFromNamesByValidating(
                        input.GrantedPermissionNames, UserManager, AbpSession.GetUserId());

                    await UserManager.SetGrantedPermissionsAsync(user, grantedPermissions);

                    if (AbpSession.TenantId != null)
                    {
                        var grantedMenuPermissions = PermissionManager.GetMenuPermissionsByValidating(
                            input.GrantedMenuPermissionNames, UserManager, AbpSession.GetUserId());
                        await UserManager.SetGrantedMenuPermissionsAsync(user, grantedMenuPermissions);
                    }
                }
            }
        }

        public async Task CreateOrUpdateUser(CreateOrUpdateUserInput input)
        {
            if (!input.User.Password.IsNullOrWhiteSpace())
            {
                input.User.Password = _rSACryptoService.Decrypt(input.User.Password);
            }
            await CheckUserNameUniqe(input);
            if (input.User.Id.HasValue)
            {
                await UpdateUserAsync(input);
            }
            else
            {
                await CreateUserAsync(input);
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Delete)]
        public async Task DeleteUser(EntityDto<long> input)
        {
            if (input.Id == AbpSession.GetUserId())
            {
                throw new UserFriendlyException(L("YouCanNotDeleteOwnAccount"));
            }

            var user = await UserManager.GetUserByIdAsync(input.Id);
            await _userExtensionRepository.DeleteAsync(item => item.UserId == input.Id);
            CheckErrors(await UserManager.DeleteAsync(user));
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Unlock)]
        public async Task UnlockUser(EntityDto<long> input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            user.Unlock();
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Edit)]
        protected virtual async Task UpdateUserAsync(CreateOrUpdateUserInput input)
        {
            Debug.Assert(input.User.Id != null, "input.User.Id should be set.");

            var user = await UserManager.FindByIdAsync(input.User.Id.Value.ToString());

            //Update user properties
            ObjectMapper.Map(input.User, user); //Passwords is not mapped (see mapping configuration)

            var currentUser = await GetCurrentUserAsync();

            if (user.AdministratorWeight != input.AdministratorWeight)
            {
                await SetUserLevel(input, user, currentUser);
            }
            if (user.CultureName.IsNullOrEmpty())
            {
                await SetDefalutCultureName(user);
            }

            CheckErrors(await UserManager.UpdateAsync(user));

            if (input.SetRandomPassword)
            {
                var randomPassword = await UserManager.CreateRandomPassword();
                user.Password = _passwordHasher.HashPassword(user, randomPassword);
                input.User.Password = randomPassword;
            }
            else if (!input.User.Password.IsNullOrEmpty())
            {
                await UserManager.InitializeOptionsAsync(AbpSession.TenantId);
                CheckErrors(await UserManager.ChangePasswordAsync(user, input.User.Password));
            }

            await SetUserRoles(user, input, currentUser);
            await SetUserUnits(user, input);
            await SetMainUnit(input, user);

            if (input.SendActivationEmail)
            {
                user.SetNewEmailConfirmationCode();
                await _userEmailer.SendEmailActivationLinkAsync(
                    user,
                    AppUrlService.CreateEmailActivationUrlFormat(AbpSession.TenantId),
                    input.User.Password
                );
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Create)]
        protected virtual async Task CreateUserAsync(CreateOrUpdateUserInput input)
        {
            if (AbpSession.TenantId.HasValue)
            {
                await _userPolicy.CheckMaxUserCountAsync(AbpSession.GetTenantId());
            }

            var user = ObjectMapper.Map<User>(input.User); //Passwords is not mapped (see mapping configuration)
            user.TenantId = AbpSession.TenantId;

            //Set password
            if (input.SetRandomPassword)
            {
                var randomPassword = await UserManager.CreateRandomPassword();
                user.Password = _passwordHasher.HashPassword(user, randomPassword);
                input.User.Password = randomPassword;
            }
            else if (!input.User.Password.IsNullOrEmpty())
            {
                await UserManager.InitializeOptionsAsync(AbpSession.TenantId);
                foreach (var validator in _passwordValidators)
                {
                    CheckErrors(await validator.ValidateAsync(UserManager, user, input.User.Password));
                }
                user.Password = _passwordHasher.HashPassword(user, input.User.Password);
            }

            user.ShouldChangePasswordOnNextLogin = input.User.ShouldChangePasswordOnNextLogin;

            var currentUser = await GetCurrentUserAsync();

            await SetUserLevel(input, user, currentUser);
            await SetDefalutCultureName(user);

            CheckErrors(await UserManager.CreateAsync(user));
            await CurrentUnitOfWork.SaveChangesAsync(); //To get new user's Id.

            await SetUserRoles(user, input, currentUser);
            await SetUserUnits(user, input);
            await SetMainUnit(input, user);

            //Notifications
            await _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync(user.ToUserIdentifier());
            await _appNotifier.WelcomeToTheApplicationAsync(user);

            //Send activation email
            if (input.SendActivationEmail)
            {
                user.SetNewEmailConfirmationCode();
                await _userEmailer.SendEmailActivationLinkAsync(
                    user,
                    AppUrlService.CreateEmailActivationUrlFormat(AbpSession.TenantId),
                    input.User.Password
                );
            }
        }

        private async Task SetMainUnit(CreateOrUpdateUserInput input, User user)
        {
            if (user.Id == 0 || user.Id == AbpSession.UserId)
            {
                return;
            }

            if ((input.OrganizationUnitId != null && input.OrganizationUnitId != 0) 
                && !input.OrganizationUnits.Contains(input.OrganizationUnitId.Value))
            {
                throw new UserFriendlyException(L("MainOrganizationUnitVaild"));
            }

            if (input.OrganizationUnitId.HasValue && input.OrganizationUnitId > 0)
            {
                var userExtension = await _userExtensionRepository.FirstOrDefaultAsync(c => c.UserId == user.Id);
                if (userExtension == null)
                {
                    userExtension = new UserExtension
                    {
                        UserId = user.Id,
                        MainUnitId = input.OrganizationUnitId.Value
                    };
                    await _userExtensionRepository.InsertAsync(userExtension);
                }
                else
                {
                    userExtension.MainUnitId = input.OrganizationUnitId.Value;
                    await _userExtensionRepository.UpdateAsync(userExtension);
                }
            }
        }

        private async Task SetUserRoles(User user, CreateOrUpdateUserInput input, User currentUser)
        {
            /*
             用户不可以修改自己的权限，超级管理员不需要绑定权限
             (用户改自己的权限，因为受范围缩写，只能缩小不能放大，而缩小了大概率是失误操作)
             */
            if (user.Id > 0 && user.Id != AbpSession.UserId)
            {
                var superVal = LevelEnum.Super.RawValue();
                if (user.AdministratorWeight < superVal)
                {
                    //Update roles
                    var roleNames = new List<string>();
                    foreach (var item in input.AssignedRoleNames)
                    {
                        if (currentUser.AdministratorWeight >= superVal || await UserManager.IsInRoleAsync(currentUser, item))
                        {
                            roleNames.Add(item);
                        }
                        else 
                        {
                            // 或者角色是本人创建的，先不校验角色内的权限了
                            var role = await _roleManager.FindByNameAsync(item);
                            if(role != null && role.CreatorUserId == currentUser.Id)
                            {
                                roleNames.Add(item);
                            }
                        }
                    }

                    CheckErrors(await UserManager.SetRolesAsync(user, roleNames.ToArray()));
                }
            }
        }

        private async Task SetUserUnits(User user, CreateOrUpdateUserInput input)
        {
            /*
             用户不可以修改自己的权限，超级管理员不需要绑定权限
             */
            if (user.Id > 0 && user.Id != AbpSession.UserId)
            {
                //update organization units
                await UserManager.SetOrganizationUnitsAsync(user, input.OrganizationUnits.ToArray());
            }
        }

        private async Task SetUserLevel(CreateOrUpdateUserInput input, User user, User currentUser)
        {
            if (await IsGrantedAsync(AppPermissions.Pages_Administration_Users_ChangeLevel))
            {
                /*
                用户不能提升自己的等级，上限必须低于当前用户的等级
                */
                if(currentUser.AdministratorWeight > input.AdministratorWeight && currentUser.Id != user.Id)
                {
                    user.AdministratorWeight = input.AdministratorWeight;
                }
            }
        }

        private async Task SetDefalutCultureName(User user)
        {
            if(AbpSession.TenantId != null)
            {
                var languages = (await _applicationLanguageManager.GetLanguagesOfSingleTenantAsync(AbpSession.TenantId))
                    .OrderBy(l => l.DisplayName)
                    .ToList();

                if(languages.Count > 0)
                {
                    user.CultureName = languages[0].Name;
                }
            }
        }

        private async Task CheckUserNameUniqe(CreateOrUpdateUserInput input)
        {
            var user = await UserManager.Users.FirstOrDefaultAsync(item => item.Name == input.User.Name);

            if (user != null)
            {
                if (input.User.Id == null)
                {
                    throw new UserFriendlyException("该用户姓名已存在，请重新添加");
                }
                else
                {
                    if (user.Id != input.User.Id)
                    {
                        throw new UserFriendlyException("该用户姓名已存在，请重新添加");
                    }
                }

            }
        }
        #endregion



        private async Task FillRoleNames(IReadOnlyCollection<UserListDto> userListDtos)
        {
            /* This method is optimized to fill role names to given list. */
            var userIds = userListDtos.Select(u => u.Id);

            var userRoles = await _userRoleRepository.GetAll()
                .Where(userRole => userIds.Contains(userRole.UserId))
                .Select(userRole => userRole).ToListAsync();

            var distinctRoleIds = userRoles.Select(userRole => userRole.RoleId).Distinct();

            foreach (var user in userListDtos)
            {
                var rolesOfUser = userRoles.Where(userRole => userRole.UserId == user.Id).ToList();
                user.Roles = ObjectMapper.Map<List<UserListRoleDto>>(rolesOfUser);
            }

            var roleNames = new Dictionary<int, string>();
            var roleOrders = new Dictionary<int, int>();
            foreach (var roleId in distinctRoleIds)
            {
                var role = await _roleManager.FindByIdAsync(roleId.ToString());
                if (role != null)
                {
                    roleNames[roleId] = role.DisplayName;
                    roleOrders[roleId] = role.Order;
                }
            }

            foreach (var userListDto in userListDtos)
            {
                foreach (var userListRoleDto in userListDto.Roles)
                {
                    if (roleNames.ContainsKey(userListRoleDto.RoleId))
                    {
                        userListRoleDto.RoleName = roleNames[userListRoleDto.RoleId];
                        userListRoleDto.Order = roleOrders[userListRoleDto.RoleId];
                    }
                }

                userListDto.Roles = userListDto.Roles.Where(r => r.RoleName != null).OrderByDescending(r=>r.Order).ThenBy(r => r.RoleName).ToList();
            }
        }
        private async Task FillUnitNames(List<UserListDto> userListDtos)
        {
            var userIds = userListDtos.Select(u => u.Id);

            var userUnits = await _userOrganizationUnitRepository.GetAll()
                .Where(userUnit => userIds.Contains(userUnit.UserId))
                .Select(userUnit => userUnit).ToListAsync();

            var distinctUnitIds = userUnits.Select(userUnit => userUnit.OrganizationUnitId).Distinct();

            foreach (var user in userListDtos)
            {
                var unitsOfUser = userUnits.Where(userUnit => userUnit.UserId == user.Id).ToList();
                user.Units = ObjectMapper.Map<List<UserListUnitDto>>(unitsOfUser);
            }

            var unitNames = new Dictionary<long, string>();
            var unitOrders = new Dictionary<long, string>();
            foreach (var unitId in distinctUnitIds)
            {
                var organizationUnit = await _organizationUnitRepository.FirstOrDefaultAsync(unitId);
                
                if (organizationUnit != null)
                {
                    unitNames[unitId] = organizationUnit.ShortName;
                    unitOrders[unitId] = organizationUnit.Code;
                }
            }

            foreach (var userListDto in userListDtos)
            {
                foreach (var userListUnitDto in userListDto.Units)
                {
                    if (unitNames.ContainsKey(userListUnitDto.OrganizationUnitId))
                    {
                        userListUnitDto.DisplayName = unitNames[userListUnitDto.OrganizationUnitId];
                        userListUnitDto.Code = unitOrders[userListUnitDto.OrganizationUnitId];
                    }
                }

                userListDto.Units = userListDto.Units.Where(r => r.DisplayName != null).OrderBy(r => r.Code).ToList();
            }
        }


        private IQueryable<User> GetUsersFilteredQuery(IGetUsersInput input, int currentUserAdministratorWeight)
        {
            var query = UserManager.Users
                /*按管理等级过滤（一个普通管理员，不应该能修改超级管理员的资料）*/
                .Where(u => u.AdministratorWeight <= currentUserAdministratorWeight)
                .WhereIf(input.Role.HasValue, u => u.Roles.Any(r => r.RoleId == input.Role.Value))
                .WhereIf(input.Unit.HasValue,u=>u.OrganizationUnits.Any(r => r.OrganizationUnitId == input.Unit.Value))
                .WhereIf(input.OnlyLockedUsers, u => u.LockoutEndDateUtc.HasValue && u.LockoutEndDateUtc.Value > DateTime.UtcNow)
                .WhereIf(
                    !input.Filter.IsNullOrWhiteSpace(),
                    u =>
                        u.Name.Contains(input.Filter) ||
                        u.Surname.Contains(input.Filter) ||
                        u.UserName.Contains(input.Filter) ||
                        u.EmailAddress.Contains(input.Filter)
                );

            int superWeight = LevelEnum.Super.WeightValue();

            List<string> permissionFilterList = input.Permissions == null ? new List<string>() : input.Permissions.Where(p => !string.IsNullOrEmpty(p)).ToList();
            if (input.MenuPermissions != null)
            {
                permissionFilterList.AddRange(input.MenuPermissions.Where(p => !string.IsNullOrEmpty(p)));
            }

            if (permissionFilterList.Count > 0)
            {
                query = from user in query
                        join ur in _userRoleRepository.GetAll() on user.Id equals ur.UserId into urJoined
                        from ur in urJoined.DefaultIfEmpty()
                        join urr in _roleRepository.GetAll() on ur.RoleId equals urr.Id into urrJoined
                        from urr in urrJoined.DefaultIfEmpty()
                        join up in _userPermissionRepository.GetAll()
                            .Where(userPermission => permissionFilterList.Contains(userPermission.Name)) on user.Id equals up.UserId into upJoined
                        from up in upJoined.DefaultIfEmpty()
                        join rp in _rolePermissionRepository.GetAll()
                            .Where(rolePermission => permissionFilterList.Contains(rolePermission.Name)) on
                            new { RoleId = ur == null ? 0 : ur.RoleId } equals new { rp.RoleId } into rpJoined
                        from rp in rpJoined.DefaultIfEmpty()
                        where (up != null && up.IsGranted) ||
                              (up == null && rp != null && rp.IsGranted) ||
                              (user.AdministratorWeight >= superWeight)
                        select user;
            }

            return query;
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Edit)]
        public async Task SwapSortNumber(SwapSortNumberInput<long> input)
        {
            var idList = input.IdOrderList.Select(c => c.Id).ToList();
            var orderList = input.IdOrderList.Select(c => c.Order).ToList();

            if (idList.Count == 0)
            {
                return;
            }

            var list = await UserManager.Users.Where(c => idList.Contains(c.Id)).ToListAsync();
            foreach (var item in list)
            {
                var index = idList.FindIndex(c => c == item.Id);
                if (index != -1)
                {
                    item.Order = orderList[index];
                }
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Edit)]
        public async Task SetNewSorNumber(NewSortNumberInput<long> input)
        {
            var user = await UserManager.FindByIdAsync(input.Id.ToString());
            user.Order = input.NewNumber;
        }


        private async Task<int> GetMaxOrderNumber()
        {
            var query = from q in UserManager.Users
                        orderby q.Order descending
                        select q;
            var m = await query.FirstOrDefaultAsync();
            if (m != null)
            {
                return m.Order + 1;
            }
            else
            {
                return 1;
            }
        }
    }
}
